package com.tgra;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL11;

public class MovingCamera
{
	Camera cam;	
	
	Point3D eye;
	Point3D lookAt;
	Vector3D up;
	Vector3D u;
	Vector3D v;
	Vector3D n;
	
	float startTime, endTime;
	Point3D eyeP1, eyeP2, eyeP3, eyeP4;
	
	Point3D lookP1, lookP2, lookP3, lookP4;

	public MovingCamera(Point3D pEye, Point3D pCenter, Vector3D vUp)
	{
		cam = new Camera(pEye, pCenter, vUp);
		
		eye = pEye;
		lookAt = pCenter;
		up = vUp;
		
		n = Vector3D.difference(pEye, pCenter);
		n.normalize();
		u = Vector3D.cross(vUp, n);
		u.normalize();
		v = Vector3D.cross(n, u);
		
		startTime = 2.0f;
		endTime = 8.0f;
		
		eyeP1 = new Point3D(100.0f, 200.0f, 100.0f);
		eyeP2 = new Point3D(200.0f, 400.0f, 200.0f);
		eyeP3 = new Point3D(300.0f, 500.0f, 300.0f);
		eyeP4 = new Point3D(200.0f, 200.0f, 400.0f);
		
		lookP1 = new Point3D(800.0f, 1.0f, 800.0f);
		lookP2 = new Point3D(750.0f, 1.0f, 950.0f);
		lookP3 = new Point3D(100.0f, 1.0f, 600.0f);
		lookP4 = new Point3D(500.0f, 1.0f, 500.0f);
	}

	public void setModelViewMatrix()
	{
		Vector3D minusEye = Vector3D.difference(new Point3D(0,0,0), eye);
		updateNormals();
		
		float[] matrix = new float[16];
		matrix[0] = u.x;	matrix[4] = u.y;	matrix[8] = u.z;	matrix[12] = Vector3D.dot(minusEye, u);
		matrix[1] = v.x;	matrix[5] = v.y;	matrix[9] = v.z;	matrix[13] = Vector3D.dot(minusEye, v);
		matrix[2] = n.x;	matrix[6] = n.y;	matrix[10] = n.z;	matrix[14] = Vector3D.dot(minusEye, n);
		matrix[3] = 0;		matrix[7] = 0;		matrix[11] = 0;		matrix[15] = 1;

		Gdx.gl11.glMatrixMode(GL11.GL_MODELVIEW);
		Gdx.gl11.glLoadMatrixf(matrix, 0);	
	}
	
	public void updateNormals()
	{
		n = Vector3D.difference(eye, lookAt);
		n.normalize();
		u = Vector3D.cross(up, n);
		u.normalize();
		v = Vector3D.cross(n, u);
	}
	
	public void updatePosition(float elapsedTime)
	{
		if(elapsedTime < startTime)
		{
			eye.x = eyeP1.x;
			eye.y = eyeP1.y;
			eye.z = eyeP1.z;
		}
		else if(elapsedTime > endTime)
		{
			eye.x = eyeP4.x;
			eye.y = eyeP4.y;
			eye.z = eyeP4.z;
		}
		else
		{
			float t = (elapsedTime - startTime) / (endTime - startTime);
			//System.out.println("position = " + t);

			eye.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*eyeP1.x
					+ 3*(1.0f - t)*(1.0f - t)*t*eyeP2.x
					+ 3*(1.0f - t)*t*t*eyeP3.x
					+ t*t*t*eyeP4.x;

			eye.y = (1.0f - t)*(1.0f - t)*(1.0f - t)*eyeP1.y
					+ 3*(1.0f - t)*(1.0f - t)*t*eyeP2.y
					+ 3*(1.0f - t)*t*t*eyeP3.y
					+ t*t*t*eyeP4.y;

			eye.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*eyeP1.z
					+ 3*(1.0f - t)*(1.0f - t)*t*eyeP2.z
					+ 3*(1.0f - t)*t*t*eyeP3.z
					+ t*t*t*eyeP4.z;
		}
	}
	
	public void updateLookAt(float elapsedTime)
	{
		if(elapsedTime < startTime)
		{
			lookAt.x = lookP1.x;
			lookAt.y = lookP1.y;
			lookAt.z = lookP1.z;
		}
		else if(elapsedTime > endTime)
		{
			lookAt.x = lookP4.x;
			lookAt.y = lookP4.y;
			lookAt.z = lookP4.z;
		}
		else
		{
			float t = (elapsedTime - startTime) / (endTime - startTime);
			//System.out.println("position = " + t);

			lookAt.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*lookP1.x
					+ 3*(1.0f - t)*(1.0f - t)*t*lookP2.x
					+ 3*(1.0f - t)*t*t*lookP3.x
					+ t*t*t*lookP4.x;

			lookAt.y = (1.0f - t)*(1.0f - t)*(1.0f - t)*lookP1.y
					+ 3*(1.0f - t)*(1.0f - t)*t*lookP2.y
					+ 3*(1.0f - t)*t*t*lookP3.y
					+ t*t*t*lookP4.y;

			lookAt.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*lookP1.z
					+ 3*(1.0f - t)*(1.0f - t)*t*lookP2.z
					+ 3*(1.0f - t)*t*t*lookP3.z
					+ t*t*t*lookP4.z;
			//position.add(Vector3D.mult(t, Vector3D.difference(endPos, startPos)));
		}
	}
	
	public void update(float elapsedTime)
	{
		updatePosition(elapsedTime);
		updateLookAt(elapsedTime);
	}
}
